package com.gbase8c.dmt.db.oracle;

import com.gbase8c.dmt.db.object.IndexObject;
import com.gbase8c.dmt.model.migration.dto.DataSourceDto;
import com.gbase8c.dmt.model.migration.dto.IndexDto;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.dbutils.BasicRowProcessor;
import org.apache.commons.dbutils.BeanProcessor;
import org.apache.commons.dbutils.GenerousBeanProcessor;
import org.apache.commons.dbutils.RowProcessor;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ColumnListHandler;
import org.apache.commons.lang3.StringUtils;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
public class IndexObjectImpl extends MetaImpl implements IndexObject {

    public IndexObjectImpl(DataSourceDto dataSourceDto) {
        super(dataSourceDto);
    }

    @Override
    public List<String> getNames(Map<String, Object> params) {
        return null;
    }

    @Override
    public IndexDto get(String name, Map<String, Object> params) {
        return null;
    }

    @Override
    public IndexDto convert(IndexDto indexDto, Map<String, Object> params) {
        return null;
    }

    @Override
    public String sql(IndexDto indexDto, Map<String, Object> params) {
        return null;
    }

    @Override
    public List<IndexDto> getIndexDtos(String schema) {
        List<IndexDto> indexDtos = null;

        BeanProcessor beanProcessor = new GenerousBeanProcessor();
        RowProcessor rowProcessor = new BasicRowProcessor(beanProcessor);

        //先将主键查出，在查索引时将主键去掉
        String pkSql = "SELECT A.CONSTRAINT_NAME FROM ALL_CONS_COLUMNS A,ALL_CONSTRAINTS B WHERE A.constraint_name = B.constraint_name AND  B.constraint_type = 'P'" +
                "AND A.OWNER = ? ";
        List<String> pkName = query(pkSql, new ColumnListHandler<String>(),schema);
        String pk = null;
        List<String> pkNameWith = pkName.stream().map(name->wrap(name)).collect(Collectors.toList());
        if(CollectionUtils.isNotEmpty(pkNameWith)){
            pk = String.join(",",pkNameWith);
        }
        String pkWith = "("+pk+")";
        String indexesSql = "SELECT owner AS schema,INDEX_NAME as name,TABLE_OWNER,TABLE_NAME FROM ALL_INDEXES where OWNER = ? AND INDEX_NAME not in " + pkWith;
        //查到的是非主键索引
        indexDtos = query(indexesSql, new BeanListHandler<>(IndexDto.class,rowProcessor), schema);
        return indexDtos;
    }

    @Override
    public List<IndexDto> getIndexDtos(String schema, String table) {
        List<IndexDto> indexDtos = null;

        //先将主键查出，在查索引时将主键去掉
        String pkSql = "SELECT A.CONSTRAINT_NAME FROM ALL_CONS_COLUMNS A,ALL_CONSTRAINTS B WHERE A.constraint_name = B.constraint_name AND  B.constraint_type = 'P' AND A.OWNER = ? and a.table_name = ? ";
        List<String> pks = query(pkSql, new ColumnListHandler<String>(), schema,table);

        BeanProcessor beanProcessor = new GenerousBeanProcessor();
        RowProcessor rowProcessor = new BasicRowProcessor(beanProcessor);
        if (CollectionUtils.isNotEmpty(pks)) {
            List<List<String>> pkLists = Lists.newArrayList();
            if (CollectionUtils.isNotEmpty(pks)){
                pkLists = split(pks,1000);
            }

            String pkNames = null;
            StringBuilder indexesSql = new StringBuilder("SELECT table_owner AS schema,INDEX_NAME as name,TABLE_OWNER,TABLE_NAME FROM ALL_INDEXES where TABLE_OWNER = ? and TABLE_NAME = ? and index_type in('NORMAL','NORMAL/REV')");
            if (CollectionUtils.isNotEmpty(pkLists)){
                if (pkLists.size() == 1){
                    pkNames = pkLists.get(0).stream().map(s->"\'" +s + "\'").collect(Collectors.joining(","));
                    indexesSql.append("and index_name not in (" + pkNames + ")");
                } else if (pkLists.size() > 1){
                    String indexNames1 = pkLists.get(0).stream().map(s->"\'" +s + "\'").collect(Collectors.joining(","));
                    indexesSql.append("and index_name in (" + indexNames1 + ")");
                    for (int i = 1; i < pkLists.size(); i++){
                        String pkNamesi = pkLists.get(i).stream().map(s->"\'" +s + "\'").collect(Collectors.joining(","));
                        indexesSql.append("or index_name not in (" + pkNamesi + ")");
                    }
                }
            }
//            String indexesSql = "SELECT owner AS schema,INDEX_NAME as name,TABLE_OWNER,TABLE_NAME FROM ALL_INDEXES where OWNER = ? and TABLE_NAME = ? AND INDEX_NAME not in (%s)";
            indexDtos = query(indexesSql.toString(), new BeanListHandler<>(IndexDto.class, rowProcessor), schema, table);
        } else {
            String indexesSql = "SELECT table_owner AS schema,INDEX_NAME as name,TABLE_OWNER,TABLE_NAME FROM ALL_INDEXES where TABLE_OWNER = ? and TABLE_NAME = ? and index_type in('NORMAL','NORMAL/REV') ";
            indexDtos = query(indexesSql, new BeanListHandler<>(IndexDto.class, rowProcessor), schema, table);
        }
        return indexDtos;
    }

    public String wrap(String name){
        return StringUtils.wrap(name, "'");
    }

    @Override
    public IndexDto getIndexDto(String schema, IndexDto indexDto, List<String> tableSpaceNames) {
        String oracleSchema = schema;
        String tableName = indexDto.getTableName();
        String indexName = indexDto.getName();

        //查索引信息
        String indexesSql = "SELECT table_OWNER AS SCHEMA,INDEX_NAME as name,TABLE_OWNER,TABLE_NAME,INDEX_TYPE AS SRC_METHOD,TABLE_TYPE,UNIQUENESS FROM ALL_INDEXES where TABLE_OWNER = ? AND TABLE_NAME = ? AND INDEX_NAME = ?";
        //查索引相关列信息
        String indexColumnSql = "SELECT COLUMN_NAME,DESCEND AS INDEX_ORDER,COLUMN_POSITION FROM ALL_IND_COLUMNS where TABLE_OWNER = ? and index_NAME = ?";
        //查索引表空间信息
        String tableSpaceSql = "select tablespace_name from dba_indexes where TABLE_OWNER = ? AND TABLE_NAME = ? and index_name = ? and tablespace_name not in ('EXAMPLE','INDX','ODM','TOOLS','USERS','XDB','SYSTEM','UNDOTBS1','TEMP','CWMLITE','DRSYS','SYSAUX')";

        List<IndexDto.IndexColumnDto> indexColumnDtos = null;
        BeanProcessor beanProcessor = new GenerousBeanProcessor();
        RowProcessor rowProcessor = new BasicRowProcessor(beanProcessor);

        //查到的是非主键索引
        indexDto = query(indexesSql, new BeanHandler<>(IndexDto.class,rowProcessor), oracleSchema, tableName, indexName);
//        if(indexDtos != null){
//            for (IndexDto indexDto : indexDtos){
        indexDto.setIndexUnique(indexDto.isIndexUnique());
        //todo:oracle默认是以btree方式存储索引
//        indexDto.setTarMethod(AccessMethod.btree.name());
        String oracleIndex = indexDto.getName().toUpperCase();
        List<String> tableSpaceName = query(tableSpaceSql,new ColumnListHandler<String>(), oracleSchema,tableName,indexName);
        indexColumnDtos = query(indexColumnSql, new BeanListHandler<>(IndexDto.IndexColumnDto.class,rowProcessor), oracleSchema, indexName);
        //索引迁移默认开启
        indexDto.setIsMigration(Boolean.TRUE);
        //索引表空间名若不为空，将转移表空间设为开启.同时也需判断表空间是否迁移.
        if (tableSpaceName.size()!=0 && tableSpaceNames.containsAll(tableSpaceName)){
            indexDto.setTableSpaceName(tableSpaceName.get(0));
            indexDto.setIsToTableSpace(Boolean.TRUE);
        } else {
            indexDto.setIsToTableSpace(Boolean.FALSE);
        }
        //DESC排列的列名不正确，需重新设置
        for (IndexDto.IndexColumnDto indexColumnDto:indexColumnDtos){
            if (indexColumnDto.getIndexOrder().equals("DESC")){
                String indexDESCColumnsql = "select COLUMN_EXPRESSION from all_ind_expressions " +
                        "where TABLE_OWNER = ? AND TABLE_NAME = ? AND INDEX_NAME = \'" + indexDto.getName()+ "\'" +
                        " AND COLUMN_POSITION = " + indexColumnDto.getColumnPosition();
                List<String> descColumnName = query(indexDESCColumnsql, new ColumnListHandler<String>(),schema, tableName);
                indexColumnDto.setColumnName(descColumnName.get(0).replace("\"",""));
            }
        }
        indexDto.setIndexColumns(indexColumnDtos);
        return indexDto;
    }

    public List<List<String>> split(List<String> list,int size){
        if (list == null || list.size() == 0){
            return null;
        }

        int count = list.size();
        int pageCount = (count/size) + (count % size == 0 ? 0:1);
        List<List<String>> temp = Lists.newArrayList();

        for (int i = 0, from = 0, to = 0; i < pageCount; i++){
            from = i * size;
            to = from + size;
            to = to > count ? count : to;
            List<String> list1 = list.subList(from, to);
            temp.add(list1);
        }
        return temp;
    }
}
